package com.dxl.service.account;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.dxl.bean.account.RoleNode;
import com.dxl.common.enums.State;
import com.dxl.common.model.Order;
import com.dxl.common.model.Page;
import com.dxl.common.model.RespData;
import com.dxl.common.model.easyui.TreeNode;
import com.dxl.common.utils.Utils;
import com.dxl.dao.account.RoleDao;
import com.dxl.entity.account.AccountRole;
import com.dxl.entity.account.Role;
import com.dxl.entity.account.RoleFunction;
import com.dxl.service.common.BaseService;

@Service
@Transactional
public class RoleService extends BaseService {
	private static final Logger LOG = Logger.getLogger(RoleService.class);
	@Autowired
	private AccountService accountService;
	@Autowired
	private RoleDao dao;
	
	public Page<Role> list(String parentId, String keyword, Integer state, Integer pageNo, Integer pageSize) {
		if (Utils.isBlank(parentId)) {
			return this.dao.list(null, keyword, state, pageNo, pageSize);
		} else {
			Set<String> childIds = listChildIds(parentId);
			childIds.add(parentId);
			return this.dao.list(childIds.toArray(new String[0]), keyword, state, pageNo, pageSize);
		}
	}
	
	public RespData save(Role role) {
		Role srcRole;
		if (Utils.isNotBlank(role.getId())) {
			if (role.getId().equals(role.getParentId())) {
				return RespData.instance(RespData.SUCCESS, "父角色不能选自己!");
			}
			srcRole = this.get(Role.class, role.getId());
			srcRole.setName(role.getName());
			srcRole.setDescription(role.getDescription());
			srcRole.setParentId(role.getParentId());
			srcRole.setState(role.getState());
		} else {
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("name", role.getName());
			if (this.count(Role.class, params) > 0) {
				return RespData.instance(RespData.FAIL, "角色已经存在！");
			}
			srcRole = role;
		}
		if (Utils.isBlank(srcRole.getParentId())) {
			srcRole.setParentId(null);
		}
		super.save(srcRole);
		return RespData.instance(RespData.SUCCESS, srcRole.getId());
	}
	
	public RespData del(String[] ids) {
		if (Utils.isEmpty(ids)) {
			return RespData.instance(RespData.SUCCESS);
		} else {
			try {
				this.del(Role.class, ids);
				Map<String, Object> params = new HashMap<String, Object>();
				Set<String> childIds;
				for (String id : ids) {
					params.put("roleId", id);
					this.del(AccountRole.class, params);
					this.del(RoleFunction.class, params);
					childIds = listChildIds(id);
					this.del(Role.class, childIds.toArray(new String[0]));
				}
				return RespData.instance(RespData.SUCCESS);
			} catch (Exception e) {
				LOG.error(e.getMessage(), e);
				return RespData.instance(RespData.FAIL);
			}
		}
	}
	
	public RespData state(String[] ids, Integer state) {
		if (Utils.isEmpty(ids)) {
			return RespData.instance(RespData.SUCCESS);
		} else {
			try {
				Map<String, Object> params = new HashMap<String, Object>(), values = new HashMap<String, Object>();
				values.put("state", state);
				this.update(Role.class, ids, values);
				for (String id : ids) {
					params.put("roleId", id);
					this.update(AccountRole.class, params, values);
					this.update(RoleFunction.class, params, values);
					if (Utils.isNotNull(state) && State.ACTIVE.getState() == state.intValue()) {
						enableParent(id);
					}
				}
				return RespData.instance(RespData.SUCCESS);
			} catch (Exception e) {
				LOG.error(e.getMessage(), e);
				return RespData.instance(RespData.FAIL);
			}
		}
	}
	
	public Set<String> listChildIds(String parentId) {
		Set<String> childIds = new HashSet<String>();
		List<Role> childrenList = new ArrayList<Role>();
		this.getChildren(parentId, childrenList);
		for (Role child : childrenList) {
			childIds.add(child.getId());
		}
		return childIds;
	}
	
	private void getChildren(String parentId, List<Role> childrenList) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("parentId", parentId);
		params.put("state", State.ACTIVE.getState());
		List<Role> children = this.listByProps(Role.class, params);
		if (Utils.isNotEmpty(children)) {
			for (Role child : children) {
				childrenList.add(child);
				getChildren(child.getId(), childrenList);
			}
		}
	}
	
	public List<TreeNode> tree(String accountId) {
		List<TreeNode> tree = new ArrayList<TreeNode>(); 
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("state", State.ACTIVE.getState());
		paramMap.put("parentId", null);
		List<Role> topRoles = this.listByProps(Role.class, paramMap, Order.asc("name"));
		if (Utils.isEmpty(topRoles)) {
			return tree;
		}
		TreeNode node;
		Role role;
		int size = topRoles.size();
		List<String> checkedRoleIds = null;
		if (Utils.isNotNull(accountId)) {
			paramMap = new HashMap<String, Object>();
			paramMap.put("accountId", accountId);
			checkedRoleIds = this.listProp(AccountRole.class, "roleId", String.class, paramMap);
		}
		for (int i = 0; i < size; i++) {
			role = topRoles.get(i);
			node = new TreeNode(role.getId(), role.getName(), TreeNode.OPEN);
			if (Utils.isNotNull(checkedRoleIds) && checkedRoleIds.contains(role.getId())) {
				node.setChecked(TreeNode.CHECKED);
			}
			this.listChildren(node, checkedRoleIds);
			tree.add(node);
		}
		return tree;
	}
	
	private void listChildren(TreeNode node, List<String> checkedRoleIds) {
		if (Utils.isNull(node)) {
			return;
		}
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("state", State.ACTIVE.getState());
		paramMap.put("parentId", node.getId());
		List<Role> children = this.listByProps(Role.class, paramMap, Order.asc("name"));
		if (Utils.isEmpty(children)) {
			return;
		}
		if (Utils.isBlank(node.getState())) {
			node.setState(TreeNode.CLOSED);
		}
		int size = children.size();
		Role child;
		TreeNode childNode;
		List<TreeNode> childNodes = new ArrayList<TreeNode>(size);
		for (int i = 0; i < size; i++) {
			child = children.get(i);
			childNode = new TreeNode(child.getId(), child.getName());
			if (Utils.isNotNull(checkedRoleIds) && checkedRoleIds.contains(child.getId())) {
				childNode.setChecked(TreeNode.CHECKED);
			}
			childNodes.add(childNode);
			node.setChildren(childNodes);
			listChildren(childNode, checkedRoleIds);
		}
	}
	
	public List<RoleNode> treeGrid() {
		List<RoleNode> tree = new ArrayList<RoleNode>(); 
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("parentId", null);
		List<Role> topRoles = this.listByProps(Role.class, paramMap, Order.asc("name"));
		if (Utils.isEmpty(topRoles)) {
			return tree;
		}
		RoleNode node;
		Role role;
		int size = topRoles.size();
		for (int i = 0; i < size; i++) {
			role = topRoles.get(i);
			node = new RoleNode();
			node.setId(role.getId());
			node.setCreatedTime(role.getCreatedTime());
			node.setDescription(role.getDescription());
			node.setName(role.getName());
			node.setOperator(role.getOperator());
			node.setRowState(role.getState());
			node.setUpdatedTime(role.getUpdatedTime());
			this.listChildren(node);
			tree.add(node);
		}
		return tree;
	}
	
	private void listChildren(RoleNode node) {
		if (Utils.isNull(node)) {
			return;
		}
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("parentId", node.getId());
		List<Role> children = this.listByProps(Role.class, paramMap, Order.asc("name"));
		if (Utils.isEmpty(children)) {
			return;
		}
		int size = children.size();
		Role child;
		RoleNode childNode;
		List<RoleNode> childNodes = new ArrayList<RoleNode>(size);
		for (int i = 0; i < size; i++) {
			child = children.get(i);
			childNode = new RoleNode();
			childNode.setId(child.getId());
			childNode.setCreatedTime(child.getCreatedTime());
			childNode.setDescription(child.getDescription());
			childNode.setName(child.getName());
			childNode.setOperator(child.getOperator());
			childNode.setRowState(child.getState());
			childNode.setUpdatedTime(child.getUpdatedTime());
			childNodes.add(childNode);
			node.setChildren(childNodes);
			listChildren(childNode);
		}
	}
	
	public void authorize(String roleId, String[] functionIds) {
		if (Utils.isNull(roleId)) {
			return;
		}
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("roleId", roleId);
		this.del(RoleFunction.class, paramMap);
		RoleFunction roleFunction;
		if (Utils.isNotEmpty(functionIds)) {
			for (String fid : functionIds) {
				roleFunction = new RoleFunction();
				roleFunction.setRoleId(roleId);
				roleFunction.setFunctionId(fid);
				this.save(roleFunction);
			}
		}
	}
	
	private void enableParent(String id) {
		Role cur = super.get(Role.class, id);
		if (Utils.isNotNull(cur)) {
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("state", State.ACTIVE.getState());
			super.update(Role.class, new String[]{cur.getParentId()}, params);
			this.enableParent(cur.getParentId());
		}
	}
}
